/**
 * Copyright @2019 Josin All Rights Reserved.
 * Author: Josin
 * Email : xeapplee@gmail.com
 */
#ifndef FASTCJSON_FC_XML_H
#define FASTCJSON_FC_XML_H

#include <src/tool/fc_list.h>
#include <src/tool/fc_string.h>

enum /* CXML_NODE_TYPE*/
{ CXML_STYPE = 0,  CXML_NTYPE = 2 };
enum /* CXML_ROOT_TYPE */
{ CXML_SIMPLE_ROOT_TAG = 0, CXML_MULTI_ROOT_TAG = 2 };

/**
 * @brief NOTICE
 * XML node like this:
 * <info id="11" b="aa">
 *   haha
 * </info>
 */
typedef struct _FC_XML_NODE {
    char         vtp;  /* CXML_STYPE or CSML_NTYPE(FCL_LIST *) */
    CSTRING     *key;
    CSTRING     *sval; /* CXML_STYPE mode to store the string node value. */
    FCL_LIST    *val;  /* CSML_NTYPE mode to store the xml sub-nodes */
    FCL_LIST    *attrs;
} CXML_NODE;

typedef struct _FC_XML_ATTR {
    char *key;
    char *val;
    unsigned long key_len;
    unsigned long val_len;
} CXML_ATTR;

/**
 * @brief NOTICE
 * XML header like this:
 * <?xml version="1.0" encoding="UTF-8"?>
 */
typedef struct _FC_XML {
    char         xtpe;  /* Simple root tag or multi root tag */
    char        *tag;   /* xml or other tag may be */
    FCL_LIST    *attrs; /* version or encoding attr and value */
    FCL_LIST    *data;  /* XML nodes */
} CXML;

int    trash_cxml(CXML *v);
#define CXML_API
CXML_API CXML  *new_cxml_from_string2(char *str, unsigned long long);
CXML_API char  *new_string_from_cxml(CXML *c);
CXML_API char  *new_cxml_get_error();
CXML_API CXML_NODE *cxml_make_node(char *name, unsigned long nlen, char *text, unsigned long tlen);
CXML_API int cxml_node_add_attr(CXML_NODE *cnode, char *key, unsigned long klen, char *val, unsigned long vlen);
CXML_API int cxml_node_add_node(CXML_NODE *cnode, CXML_NODE *snode);
CXML_API CXML *cxml_new_cxml(char *tag, char *version, char *encoding);
CXML_API int cxml_add_root_node(CXML *xml, CXML_NODE *node);

#define CXML_LOOP_FREACH_DATA(l, c) do { if ( !l ) break;\
    FCL_NODE  *__fnode;\
    CXML_NODE *__cnode;\
    FCL_LIST_FOREACH_HEAD(l, __fnode) {\
        __cnode = FCL_NODE_DATA_P(__fnode);\
        c = __cnode;
#define CXML_LOOP_FREACH_ATTR(l, c) do { if ( !l ) break;\
    FCL_NODE  *__fnode;\
    CXML_ATTR *__cattr;\
    FCL_LIST_FOREACH_HEAD(l, __fnode) {\
        __cattr = FCL_NODE_DATA_P(__fnode);\
        c = __cattr;
#define CXML_LOOP_FOREACH_END()\
    } FCL_LIST_FOREACH_END(); }while(0)

/**
 * @brief NOTICE
 * Below are some macros for the easy XML parsing
 */
#define CXML_FIELD_DEF(n) \
typedef struct _CXML_FIELD_##n { CXML_NODE
#define CXML_FIELD_DEF_END(n) ;int __oth; } CXML_##n
#define CXML_FIELD_FUNC_DEF(n) \
int TRASH_CXML_##n(CXML_##n *v);\
CXML_##n *NEW_CXML_##n##_FROM_DATA(FCL_LIST *v)
#define CXML_FIELD_FUNC(n) \
CXML_##n *NEW_CXML_##n()\
{\
    CXML_##n *ptr = malloc( sizeof(CXML_##n) );\
    if (!ptr) {\
        return NULL;\
    }\
    e_memzero(ptr, sizeof(CXML_##n));\
    return ptr;\
}\
int TRASH_CXML_##n(CXML_##n *v)\
{\
    if(!v) return TRUE;\
    e_memfree(v);\
    return TRUE;\
}\
CXML_##n *NEW_CXML_##n##_FROM_DATA(FCL_LIST *v)\
{\
    CXML_##n  *res;\
    if (!v) {\
        return NULL;\
    }\
    res = NEW_CXML_##n();\
    if (!res) {\
        return NULL;\
    }\
    FCL_NODE    *fnode;\
    CXML_NODE   *xnode;\
    FCL_LIST_FOREACH_HEAD(v, fnode) {\
        xnode = FCL_NODE_DATA_P(fnode);\
        if (!xnode) {\
            TRASH_CXML_##n(res);\
            return NULL;\
        }
#define CXML_FIELD_CMP(name, aname, l, e)\
        e ( e_str##l##cmp(xnode->key->s, #name) ) {\
            res->aname = xnode;\
        }
#define CXML_FIELD_INDEX_CMP(aname, ik, e)\
        e ( __i == (ik) && (ik) != -1 ) {\
            res->aname = xnode;\
        }
#define CXML_FIELD_FUNC_END()\
        else {\
            res->__oth = 1;\
        }\
    } FCL_LIST_FOREACH_END();\
    return res;\
}

/**
 * @brief NOTICE
 * Below are some macros for Parsing the XML attrs
 */
#define CXML_ATTR_DEF(n) \
typedef struct _CXML_ATTR_##n { CXML_ATTR
#define CXML_ATTR_DEF_END(n) ;int __oth; } CXML_##n
#define CXML_ATTR_FUNC_DEF(n) \
int TRASH_CXML_##n(CXML_##n *v);\
CXML_##n *NEW_CXML_##n##_FROM_ATTR(FCL_LIST *v)
#define CXML_ATTR_FUNC(n) \
CXML_##n *NEW_CXML_##n()\
{\
    CXML_##n *ptr = malloc( sizeof(CXML_##n) );\
    if (!ptr) {\
        return NULL;\
    }\
    e_memzero(ptr, sizeof(CXML_##n));\
    return ptr;\
}\
int TRASH_CXML_##n(CXML_##n *v)\
{\
    if(!v) return TRUE;\
    e_memfree(v);\
    return TRUE;\
}\
CXML_##n *NEW_CXML_##n##_FROM_ATTR(FCL_LIST *v)\
{\
    CXML_##n  *res;\
    if (!v) {\
        return NULL;\
    }\
    res = NEW_CXML_##n();\
    if (!res) {\
        return NULL;\
    }\
    FCL_NODE    *fnode;\
    CXML_ATTR   *xattr;\
    FCL_LIST_FOREACH_HEAD(v, fnode) {\
        xattr = FCL_NODE_DATA_P(fnode);\
        if (!xattr) {\
            TRASH_CXML_##n(res);\
            return NULL;\
        }
#define CXML_ATTR_CMP(name, aname, l, e)\
        e (e_str##l##cmp(xattr->key, #name)) {\
            res->aname = xattr;\
        }
#define CXML_ATTR_INDEX_CMP(aname, ik, e)\
        e ( __i == (ik) && (ik) != -1 ) {\
            res->aname = xattr;\
        }
#define CXML_ATTR_FUNC_END()\
        else {\
            res->__oth = 1;\
        }\
    } FCL_LIST_FOREACH_END();\
    return res;\
}

#endif /* FASTCJSON_FC_XML_H */
